package com.eva.config.security;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.eva.core.servlet.ServletDuplicateInputStream;
import com.eva.core.servlet.ServletDuplicateRequestWrapper;
import com.eva.core.utils.Utils;
import com.eva.dao.system.model.SystemInterfaceConfig;
import com.eva.service.system.SystemInterfaceConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 请求参数过滤器，实现参数的解密和重新注入
 * @author Caesar Liu
 * @date 2022-04-04 11:42
 */
@Slf4j
@Component
@WebFilter(urlPatterns = "/*", filterName = "requestParamFilter")
public class SecurityRequestFilter implements Filter {

    @Autowired
    private SystemInterfaceConfigService systemInterfaceConfigService;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        // 不需要加密
        if (Utils.Secure.disallowEncrypt(httpServletRequest)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        // URI不匹配
        String uri = httpServletRequest.getRequestURI();
        uri = uri.replace(httpServletRequest.getContextPath(), "");
        SystemInterfaceConfig interfaceConfig = systemInterfaceConfigService.match(uri);
        if (interfaceConfig == null || !interfaceConfig.getEnableEncrypt()) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 防止请求流被拦截器进行一次读取后关闭导致流无法连续读取的问题
        ServletDuplicateRequestWrapper requestWrapper = new ServletDuplicateRequestWrapper(httpServletRequest);
        ServletDuplicateInputStream duplicateInputStream = ((ServletDuplicateInputStream)requestWrapper.getInputStream());
        String body = duplicateInputStream.getBody();
        // URL参数处理
        String requestParameter = servletRequest.getParameter("_p");
        // - 存在其他参数 && 不存在_p参数，则视为请求参数未进行加密
        if (servletRequest.getParameterNames().hasMoreElements() && StringUtils.isBlank(requestParameter)) {
            throw new IllegalArgumentException("EVA: request parameter is fault.");
        }
        if (StringUtils.isNotBlank(requestParameter)) {
            try {
                requestParameter = Utils.Secure.decryptRequest(requestParameter);
                JSONObject paramsJson = JSON.parseObject(requestParameter);
                for (String key : paramsJson.keySet()) {
                    requestWrapper.addParameter(key, paramsJson.get(key));
                }
            } catch (SecurityException e) {
                throw new IllegalArgumentException("EVA: decrypt request parameter throw an exception.", e);
            }
        }
        // body参数处理
        if (StringUtils.isNotBlank(body)) {
            JSONObject jsonBody;
            try {
                jsonBody = JSON.parseObject(body);
            } catch (Exception e) {
                throw new IllegalArgumentException("EVA: request body is fault.");
            }
            String requestBody = jsonBody.getString("_p");
            if (jsonBody.keySet().size() > 0 && StringUtils.isBlank(requestBody)) {
                throw new IllegalArgumentException("EVA: request body is fault.");
            }
            try {
                duplicateInputStream.setBody(Utils.Secure.decryptRequest(requestBody));
            } catch (SecurityException e) {
                throw new IllegalArgumentException("EVA: decrypt request body throw an exception.", e);
            }
        }
        filterChain.doFilter(requestWrapper, servletResponse);
    }

}
